import EventEmitter from '@/utils/EventEmitter'
import { useEffect, useRef, useState } from 'react'
import styles from './style.module.scss'
import { sleep, UUID } from '../common'
export interface ContextMenuProps {
  label: string
  key: string
  children?: ContextMenuProps[]
}
export type ContextMenuCallback = (key: string) => any

type ContextMenuEvent = {
  show: (
    props: ContextMenuProps[],
    callback: ContextMenuCallback,
    pos?: {
      x: number
      y: number
    }
  ) => void
}

export const contextMenuEvent = new EventEmitter<ContextMenuEvent>()

const cellWidth = 170
const cellHeight = 30
const ContextMenu = () => {
  const [contextMenu, setContextMenu] = useState<ContextMenuProps[]>([])
  const callback = useRef<ContextMenuCallback | null>(null)
  const [show, setShow] = useState(false)
  const pos = useRef<{ x: number; y: number }>({ x: 0, y: 0 })
  const [{ clientWidth, clientHeight }, setClientSize] = useState({
    clientWidth: 0,
    clientHeight: 0,
  })
  const [showPos, setShowPos] = useState<{ x: number; y: number }>({
    x: 0,
    y: 0,
  })
  const [_windowSize, setWindowSize] = useState({
    width: 0,
    height: 0,
  })
  useEffect(() => {
    const onWindowResize = () => {
      setWindowSize({ width: window.innerWidth, height: window.innerHeight })
      setClientSize({
        clientWidth: document.body.clientWidth,
        clientHeight: document.body.clientHeight,
      })
    }
    window.addEventListener('resize', onWindowResize)
    onWindowResize()
    return () => window.removeEventListener('resize', onWindowResize)
  }, [])
  const inner = useRef(false)
  const uuid = useRef('')
  useEffect(() => {
    if (!show) callback.current = null
    if (show) inner.current = false
    uuid.current = UUID()
  }, [show])
  useEffect(() => {
    const onMouseMove = (e: MouseEvent) => {
      const mousePos = {
        x: e.clientX + 2,
        y: e.clientY - 2,
      }
      pos.current = mousePos
    }
    const onTouchStart = (e: TouchEvent) => {
      const touchPos = {
        x: e.touches[0].clientX + 2,
        y: e.touches[0].clientY - 2,
      }
      pos.current = touchPos
    }
    window.addEventListener('mousemove', onMouseMove)
    window.addEventListener('touchstart', onTouchStart)
    const onShow = async (
      props: ContextMenuProps[],
      callback2: ContextMenuCallback,
      pos2?: {
        x: number
        y: number
      }
    ) => {
      callback.current = callback2
      setContextMenu([...props])
      setShowPos(pos2 || pos.current)
      setShow(true)
      uuid.current = UUID()
      await sleep(10)
      window.addEventListener(
        'mousedown',
        () => {
          !inner.current && setShow(false)
        },
        {
          once: true,
        }
      )
    }
    contextMenuEvent.on('show', onShow)
    return () => {
      contextMenuEvent.off('show', onShow)
      window.removeEventListener('mousemove', onMouseMove)
      window.removeEventListener('touchstart', onTouchStart)
    }
  }, [])
  if (show) {
    const style: React.CSSProperties = {}
    style[`left`] = showPos.x
    style[`top`] = showPos.y
    let translateX = '0%'
    let translateY = '0%'
    if (clientWidth - showPos.x < cellWidth) {
      translateX = `${-cellWidth}px`
    }
    if (clientHeight - showPos.y < cellHeight * contextMenu.length) {
      translateY = `${-cellHeight * contextMenu.length}px`
    }
    style[`transform`] = `translate(${translateX}, ${translateY})`

    return (
      <div
        key={uuid.current}
        onMouseEnter={() => (inner.current = true)}
        onMouseLeave={() => (inner.current = false)}
        onContextMenu={(e) => {
          e.preventDefault()
          setShow(false)
        }}
        className={styles['content-menu-component']}
        style={style}>
        {contextMenu.map((item) => (
          <div
            className={styles['content-menu-item']}
            onMouseUp={() => {
              try {
                const call = callback.current
                callback.current = null
                if (call) {
                  call(item.key)
                }
              } finally {
                setShow(false)
              }
            }}
            key={item.key}>
            {item.label}
          </div>
        ))}
      </div>
    )
  }

  return <></>
}
export function showContextMenu(
  props: ContextMenuProps[],
  callback: ContextMenuCallback,
  pos?: {
    x: number
    y: number
  }
) {
  contextMenuEvent.emit('show', props, callback, pos)
}
export default ContextMenu
